﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using XMLGener.Data;
using XMLGener.Utils;
using XMLGener.GUI.components;
using System.IO;
using XMLGener.Interfaces;

namespace XMLGener.GUI
{
    /// <summary>
    /// Delegated method for event when slected node was changed.s
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="node"></param>
    public delegate void SelectedTreeNodeChanged(XTemplatePanel sender, XTreeNode node);

    /// <summary>
    /// Delegate for opening document on doubleclick in included files list.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="filename"></param>
    public delegate void OpenDocument(XTemplatePanel sender, string filename);


    /// <summary>
    /// Visualised X-Template document.
    /// </summary>
    public partial class XTemplatePanel : UserControl
    {
        /// <summary>
        /// Event is dispatched if tree node is selected (by user or programmatic   
        /// </summary>
        public event SelectedTreeNodeChanged onTreeNodeSelect;

        /// <summary>
        /// 
        /// </summary>
        public event OpenDocument openDocumentEvent;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="parentTab"></param>
        public XTemplatePanel(string fileName, TabPage parentTab)
        {
            this.parentTab = parentTab;
            InitializeComponent();
            customInitializeComponent();
            if (fileName == null)
                createNew();
            else
                load(fileName);
            showSelectedNode();
            refreshTabText();
        }

        private void customInitializeComponent()
        {

            this.selectOutputFile.InitialDirectory = DirectoriesUtil.outputDir.FullName;
            this.openXTLDialog.InitialDirectory = DirectoriesUtil.templatesDir.FullName;
        }


        /// <summary>
        /// 
        /// </summary>
        public TabPage parentTab = null;
        
        /// <summary>
        /// 
        /// </summary>
        public XMLGenerDocument doc = null;
        
        /// <summary>
        /// 
        /// </summary>
        private void createNew()
        {
            this.doc = new XMLGenerDocument();
            XTreeNode rootNode = XTreeNode.createStructure(doc.getMainElement());
            if (rootNode != null)
                xmlTreeView.Nodes.Add(rootNode);
            XTreeNode typesNode = XTreeNode.createStructure(doc.getTypesElement());
            if (typesNode != null)
            {
                typesNode.showContentType = false;
                xmlTreeView.Nodes.Add(typesNode);
            }
            XTreeNode dataTypesNode = XTreeNode.createStructure(doc.getDataTypesElement());
            if (dataTypesNode != null)
            {
                dataTypesNode.showContentType = false;
                xmlTreeView.Nodes.Add(dataTypesNode);
            }
            this.selectedTreeNode = rootNode;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        private void load( string filename)
        {
            doc = XMLGenerDocument.loadDocumentForEdit(filename);
            XTreeNode rootNode = XTreeNode.createStructure(doc.getMainElement());
            XTreeNode typesNode = XTreeNode.createStructure(doc.getTypesElement());
            XTreeNode dataTypesNode = XTreeNode.createStructure(doc.getDataTypesElement());

            if (rootNode == null)
            {
                XLogger.addError(this.GetType().ToString(), "Error in getting main element");
                return;
            }
            if (typesNode == null)
            {
                XLogger.addError(this.GetType().ToString(), "Error in getting types element");
                return;
            }
            if (dataTypesNode == null)
            {
                XLogger.addError(this.GetType().ToString(), "Error in getting  data types element");
                return;
            }
            typesNode.showContentType = false;
            dataTypesNode.showContentType = false;
            xmlTreeView.Nodes.Add(rootNode);
            xmlTreeView.Nodes.Add(typesNode);
            xmlTreeView.Nodes.Add(dataTypesNode);

            
            this.selectedTreeNode = rootNode;
            showOutSettings();

        }



        private void showOutSettings()
        {
            if (this.doc == null)
                return;
            this.tbOutId.Text = doc.outId;
            refreshIncludedFiles();
            refreshPreGeneratedFiles();

            
            cbOutputModules.Items.Clear();
            cbFinalModule.Items.Clear();

            string outModId = this.doc.module;
            if (outModId == null)
                outModId = "none";

            if (!XModuleManager.modOutputList.ContainsKey(outModId))
                outModId = "none";

            string secondOutModId = this.doc.secondModule;
            if (secondOutModId == null)
                secondOutModId = "none";

            if (!XModuleManager.modOutputList.ContainsKey(secondOutModId))
                secondOutModId = "none";
            

            cbOutputModules.Items.AddRange(XModuleManager.modOutputList.Values.ToArray());
            cbOutputModules.SelectedItem = XModuleManager.modOutputList[outModId];
            cbFinalModule.Items.AddRange(XModuleManager.modOutputList.Values.ToArray());
            cbFinalModule.SelectedItem = XModuleManager.modOutputList[secondOutModId];


            this.tbSourceFile.Text = doc.sourceFile;
            this.tbOutputFile.Text = doc.outFile;
            this.tbRanomInit.Value = doc.randomInit;
            this.tbDocCount.Value = doc.documentsCount;

            if ("xsd"==doc.outSchemeType)
                this.rbGenerXSD.Checked = true;
            else if ("none"==doc.outSchemeType)
                this.rbGenerNone.Checked = true;
            else
                this.rbGenerDTD.Checked = true;
        }

        /// <summary>
        /// 
        /// </summary>
        private void refreshTabText()
        {
            if (this.parentTab == null || this.doc == null ||
                this.doc.getMainElement() == null )
                return;
            this.parentTab.Text = this.doc.getMainElement().name;
                    
        }

       

        /// <summary>
        /// 
        /// </summary>
        private XTreeNode selectedTreeNode = null;

        /// <summary>
        /// Return selected TreeNode
        /// </summary>
        public XTreeNode getSelectedTreeNode
        { 
            get {return selectedTreeNode;}
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void xmlTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            selectedTreeNode = (XTreeNode)this.xmlTreeView.SelectedNode;
            showSelectedNode();
        }

        /// <summary>
        /// Set selected tree node
        /// </summary>
        public void refreshTreeView()
        {
            selectedTreeNode = (XTreeNode)this.xmlTreeView.SelectedNode;
        }

        /// <summary>
        /// Idicator, if component content is changed programmatically.
        /// It causes, that event method, which is called in component's 
        /// change, is not executed.
        /// </summary>
        private bool programmaticallyChange = false;

        private bool selectedNodeIsText = false;

        private void setSelectedNode(XTreeNode node)
        {
            if (node == null)
            {
                node = (XTreeNode)this.xmlTreeView.Nodes[0];
            }
            this.xmlTreeView.SelectedNode = node;
            showSelectedNode();
        }
       
        /// <summary>
        /// If some node was selected, visualise this on right panel.
        /// </summary>
        private void showSelectedNode()
        {
            if (onTreeNodeSelect != null)
                onTreeNodeSelect(this,selectedTreeNode);
            if (selectedTreeNode == null)
                return;
            programmaticallyChange = true;
            XMLGenerNode xnode= selectedTreeNode.xnode;
            tbNodeName.Text = xnode.name;
            tbId.Text = xnode.id;

            tcbNodeType.Nodes.Clear();
            tcbNodeInherit.Nodes.Clear();
            // load data types
            XDataTypeCollection list = xnode.listAvailabeTypes();
            string selectedContentType = xnode.contentType;
            XTreeNode selectedNode = null;
            
            if (list != null)
            {
                List<XTreeNode> treeList=  XTreeNode.createTypeStructure(list, selectedContentType, out selectedNode);
                if (treeList!=null)
                    tcbNodeType.Nodes.AddRange(treeList.ToArray());
                tcbNodeType.SelectedNode = selectedNode;
            }
            // load parent types for inheritation
            list = xnode.listAvailabeParents();
            selectedContentType = xnode.parentTypeName;
            selectedNode = null;
            
            if (list != null)
            {
                List<XTreeNode> treeList = XTreeNode.createTypeStructure(list, selectedContentType, out selectedNode);
                if (treeList != null)
                    tcbNodeInherit.Nodes.AddRange(treeList.ToArray());
                tcbNodeInherit.SelectedNode = selectedNode;
            }

            // update GUI
            bool nameVisible = false;
            bool minMaxVisible = false;
            bool modulesVisible = false;
            bool calculationVisible = false;
            bool dataTypeVisible = false;
            bool nodeTypeVisible = true;
            selectedNodeIsText = false;
            bool disableAll = false;
            bool inheritedVisible = false;
            bool elementIdVisible = false;
            bool containerNodeVisible = false;
            bool nodeIsElements = false;
            bool editingEnabled = true;
            bool isInherited = false; 

            if (xnode is XMLGenerElement)
            {
                XMLGenerElement elem = xnode as XMLGenerElement;
                string selemTp = XMLGenerElement.TYPE_ONLY_ELEMENTS;
                if (elem.contentType != selemTp)
                    selectedNodeIsText = true;
                if (elem.baseType != null)
                    isInherited = true;
            }

            if ((xnode is XMLGenerElementTypes )||
                (xnode is XMLGenerDataTypes))
            {
                disableAll = true;
            }
            else if (xnode is XDataType) 
            {
                nameVisible = true;
                dataTypeVisible = true;
                nodeTypeVisible = false;
                inheritedVisible = true;
                calculationVisible = false;
                pDataTypeComponent.setDataType(xnode as XDataType);
            }else
            if (xnode is XMLGenerAttribute)
            {
                selectedNodeIsText = true;
                //XMLGenerAttribute xattr = (XMLGenerAttribute)xnode;
                nameVisible = true;
                modulesVisible = true;
                calculationVisible = false;
                inheritedVisible = false;
            }else
            if (xnode is XMLGenerRangeElement)
            {
                XMLGenerRangeElement xelem = (XMLGenerRangeElement)xnode;
                nodeIsElements = (xnode is XMLGenerElements);
                bool isMainElement = (xnode is XMLGenerMainElement);
                bool isTypeElement = (xnode is XMLGenerElementType);
                bool useFreq = xelem.useFrequency;
                bool useDepth = xelem.useDepth;
                bool useFanout = xelem.useFanout;

                nodeTypeVisible = !isTypeElement && !isInherited;
                elementIdVisible = isTypeElement;
                selectedNodeIsText = ((xnode is XMLGenerTextNode) || selectedNodeIsText) && !nodeIsElements;
                modulesVisible = selectedNodeIsText && !nodeIsElements;
                inheritedVisible = !nodeIsElements && !isTypeElement;
                nameVisible = !nodeIsElements;
                minMaxVisible = true;
                containerNodeVisible = !selectedNodeIsText;
                tbMaxCount.Enabled = !useFreq && !isMainElement;
                tbMinCount.Enabled = !useFreq && !isMainElement;
                tbMinFrequency.Enabled = useFreq && !isMainElement;
                tbMaxFrequency.Enabled = useFreq && !isMainElement;
                chbFrequency.Enabled = !isMainElement;
                tbMinDepth.Enabled = useDepth && !selectedNodeIsText;
                tbMaxDepth.Enabled = useDepth && !selectedNodeIsText;
                tbMinFanout.Enabled = !selectedNodeIsText && useFanout;
                tbMaxFanout.Enabled = !selectedNodeIsText && useFanout;
                chbUseFanout.Enabled = !selectedNodeIsText;
                chbDepth.Enabled = !selectedNodeIsText;

                tbMinCount.Value = xelem.minCount;
                tbMaxCount.Value = xelem.maxCount;
                tbMinDepth.Value = xelem.minDepth;
                tbMaxDepth.Value = xelem.maxDepth;
                tbMinFanout.Value = xelem.minFanout;
                tbMaxFanout.Value = xelem.maxFanout;
                tbMinFrequency.Value = xelem.minFrequency;
                tbMaxFrequency.Value = xelem.maxFrequency;
                this.chbDepth.Checked = useDepth;
                this.chbFrequency.Checked = useFreq;
                this.chbUseFanout.Checked = xelem.useFanout;

                calculationVisible = true;
               
                this.lbMinChilds.Text = Convert.ToString(xelem.sumMinChMixCount);
                this.lbMaxChilds.Text = Convert.ToString(xelem.sumMaxChMixCount);
                this.lbMinTotal.Text = Convert.ToString(xelem.minTotalElemens);
                this.lbMaxTotal.Text = Convert.ToString(xelem.maxTotalElemens);
                this.lbUsedInMin.Text = Convert.ToString(xelem.countForMinTotal);
                this.lbUsedInMax.Text = Convert.ToString(xelem.countForMaxTotal);

            }
            if (xnode != null && xnode.isCopy)
                editingEnabled = false;
            

            if (modulesVisible)
                loadMoulesDefinition();

            pNodeName.Visible = nameVisible && !disableAll;
            pNodeMinMax.Visible = minMaxVisible && !disableAll;
            pNodeModules.Visible = modulesVisible && !disableAll;
            pCalculation.Visible = calculationVisible && !disableAll;
            pInherited.Visible = inheritedVisible && !disableAll;
            pNodeType.Visible = nodeTypeVisible && !disableAll;
            pDataType.Visible = dataTypeVisible && !disableAll;
            moduleBox.Visible = nodeTypeVisible && !disableAll;
            //tbId.Visible = lbId.Visible = elementIdVisible ;
            pContainerNode.Visible = containerNodeVisible &&!disableAll;

            pNodeMinMax.Enabled  = editingEnabled;
            pNodeMinMax.Enabled = editingEnabled;
            pNodeModules.Enabled = editingEnabled;
            pCalculation.Enabled = editingEnabled;
            pInherited.Enabled = editingEnabled;
            pNodeType.Enabled = editingEnabled;
            pDataType.Enabled = editingEnabled;
            moduleBox.Enabled = editingEnabled;
            //tbId.Enabled = editingEnabled;
            pContainerNode.Enabled = editingEnabled;
            tbNodeName.Enabled = editingEnabled;

            programmaticallyChange = false;

        
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbNodeName_TextChanged(object sender, EventArgs e)
        {
            if (programmaticallyChange)
                return;
            selectedTreeNode.xnode.name = tbNodeName.Text;
            selectedTreeNode.refresh();
            if (selectedTreeNode.xnode == doc.getMainElement())
            {
                this.parentTab.Text = tbNodeName.Text;
            }
            showSelectedNode();
        }

       

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tcbNodeType_SelectedIndexChanged(object sender, EventArgs e)
        {
            /*if (programmaticallyChange)
                return;
            selectedTreeNode.xnode.contentType = (string)tcbNodeType.SelectedItem;
            selectedTreeNode.refresh();
            loadMoulesDefinition();
            this.showSelectedNode();*/
        }

        /// <summary>
        /// Save document.
        /// </summary>
        public void saveDocument()
        {
            doc.save();
        }

        /// <summary>
        /// Save document to selected file
        /// </summary>
        /// <param name="fileName">selected file</param>
        public void saveAsDocument(string fileName)
        {
            doc.saveAs(fileName);
            showOutSettings();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbNumeric_ValueChanged(object sender, EventArgs e)
        {
            numericValueChanged(sender);
        }

        private void tbNumeric_KeyUp(object sender, KeyEventArgs e)
        {
            numericValueChanged(sender);
        }


        private void numericValueChanged(object sender)
        {
            if (programmaticallyChange)
                return;

            if (selectedTreeNode == null || selectedTreeNode.xnode == null ||
                 !(sender is NumericUpDown))
                return;

            int intvalue = Convert.ToInt32(((NumericUpDown)sender).Value);
            decimal value =((NumericUpDown)sender).Value;

            if (sender == tbDocCount) doc.documentsCount = intvalue;

            if (selectedTreeNode.xnode is XMLGenerRangeElement)
            {
                XMLGenerRangeElement elem = (XMLGenerRangeElement)selectedTreeNode.xnode;
                if (sender == tbMaxCount) elem.maxCount = intvalue;
                else if (sender == tbMinCount) elem.minCount = intvalue;
                else if (sender == tbMaxDepth) elem.maxDepth = intvalue;
                else if (sender == tbMinDepth) elem.minDepth = intvalue;
                else if (sender == tbMinFanout) elem.minFanout = value;
                else if (sender == tbMaxFanout) elem.maxFanout = value;
                else if (sender == tbMinFrequency) elem.minFrequency = value;
                else if (sender == tbMaxFrequency) elem.maxFrequency = value;

            }
            this.showSelectedNode();
        }

        /// <summary>
        /// Create new element under selected node.
        /// </summary>
        public void addNewElement()
        {
            this.addNewNodeUnderElement(XMLGenerNode.XNodeType.ELEMENT);
        }

        /// <summary>
        /// Create new elements under selected node.
        /// </summary>
        public void addNewElements()
        {
            this.addNewNodeUnderElement(XMLGenerNode.XNodeType.ELEMENTS);
        }

        /// <summary>
        /// Create new text under selected node
        /// </summary>
        public void addNewTextNode()
        {
            this.addNewNodeUnderElement(XMLGenerNode.XNodeType.TEXTNODE);
        }

        /// <summary>
        /// Create new data type node under selected XMLGenerDataTypes node or 
        /// as last sibling node of selected XDataType node
        /// </summary>
        public void addNewDataTypeNode()
        {
            // new attribute can be created only under element
            if (this.selectedTreeNode == null || this.selectedTreeNode.xnode == null
                || (!(this.selectedTreeNode.xnode is XMLGenerDataTypes) && 
                    !(this.selectedTreeNode.xnode is XDataType)))
                return;
            XMLGenerDataTypes parentNode = null;
            XTreeNode guiParentNode = null;
            if (this.selectedTreeNode.xnode is XMLGenerDataTypes)
            {
                parentNode = (XMLGenerDataTypes)this.selectedTreeNode.xnode;
                guiParentNode = selectedTreeNode;
            }
            else 
            {
                parentNode = (XMLGenerDataTypes)((XDataType)this.selectedTreeNode.xnode).parentNode;
                guiParentNode = (XTreeNode)selectedTreeNode.Parent;
            }

            XDataType newXNode = new XDataType(parentNode);
            XTreeNode newTreeNode = new XTreeNode(newXNode);
            guiParentNode.Nodes.Insert(guiParentNode.Nodes.Count, newTreeNode);

            setSelectedNode(newTreeNode);

        }

        /// <summary>
        /// Function crates new Element(isElement=true)/Elements(isElement=false) under selected node.
        /// </summary>
        /// <param name="nodeType">type of node</param>
        private void addNewNodeUnderElement(XMLGenerNode.XNodeType nodeType) 
        {
            if (nodeType != XMLGenerNode.XNodeType.ELEMENT &&
                nodeType != XMLGenerNode.XNodeType.ELEMENTS &&
                nodeType != XMLGenerNode.XNodeType.TEXTNODE) return;
                

            // new node can be created only under element or elements
            /*if (this.selectedTreeNode == null || this.selectedTreeNode.xnode == null 
                || this.selectedTreeNode.xnode is XMLGenerAttribute 
                || this.selectedTreeNode.xnode is XMLGenerTextNode)
                return;*/
            if (this.selectedTreeNode == null || this.selectedTreeNode.xnode == null
                || this.selectedNodeIsText)
                return;

            XMLGenerNode newXNode = null;
            switch (nodeType)
            { 
                case XMLGenerNode.XNodeType.ELEMENT:
                    if (selectedTreeNode.xnode is XMLGenerElementTypes)
                        newXNode = new XMLGenerElementType("newElement", selectedTreeNode.xnode);
                    else
                        newXNode = new XMLGenerElement("newElement", selectedTreeNode.xnode);
                    break;
                case XMLGenerNode.XNodeType.ELEMENTS:
                    newXNode = new XMLGenerElements("newElements", selectedTreeNode.xnode);
                    break;
                default:
                    newXNode = new XMLGenerTextNode("text", selectedTreeNode.xnode);
                    break;
            }
                    
            XTreeNode newTreeNode  = new XTreeNode(newXNode);
            int i = selectedTreeNode.Nodes.Count - 1;
            XTreeNode childNode = null;
            for (; i >= 0; i--)
            {
                childNode = (XTreeNode) selectedTreeNode.Nodes[i];
                if (childNode!= null && !(childNode.xnode is XMLGenerAttribute ))
                {
                    selectedTreeNode.Nodes.Insert(i+1,newTreeNode);
                    break;
                }
            }
            if (i == -1)
            {
                selectedTreeNode.Nodes.Insert(0, newTreeNode);
            }
            setSelectedNode(newTreeNode);
        }


        /// <summary>
        /// Create new attribute under selected node
        /// </summary>
        public void addNewAttribute()
        {
            // new attribute can be created only under element
            if (this.selectedTreeNode == null || this.selectedTreeNode.xnode == null
                || !(this.selectedTreeNode.xnode is XMLGenerElement))
                return;

            XMLGenerAttribute newXNode = new XMLGenerAttribute("newAttribute",(XMLGenerElement) selectedTreeNode.xnode);

            XTreeNode newTreeNode = new XTreeNode(newXNode);
            selectedTreeNode.Nodes.Insert(selectedTreeNode.Nodes.Count, newTreeNode);
            
            setSelectedNode(newTreeNode);

        }


        /// <summary>
        /// Remove selected node.
        /// </summary>
        public void removeNode()
        {
            if (this.selectedTreeNode != this.xmlTreeView.Nodes[0])
            {
                this.selectedTreeNode.delete();
            }
        }

        /// <summary>
        /// Move selected node up. If node is attribute, move it maximaly
        /// behind last elemtn/elements.
        /// </summary>
        public void moveNodeUp()
        {
            XTreeNode newSelectedNode = this.selectedTreeNode.movePosition(-1);
            if (newSelectedNode != null)
            {
                selectedTreeNode = newSelectedNode;
                this.xmlTreeView.SelectedNode = selectedTreeNode;
                //this.selectedTreeNode = (XTreeNode)this.selectedTreeNode.NextNode;
                showSelectedNode();
            }

        }

        /// <summary>
        /// Move selected node up. If node is elemnt or elements, move it maximaly
        /// before first attribute.
        /// </summary>
        public void moveNodeDown()
        {
            XTreeNode newSelectedNode = this.selectedTreeNode.movePosition(1);
            if (newSelectedNode != null)
            {
                selectedTreeNode = newSelectedNode;
                this.xmlTreeView.SelectedNode = selectedTreeNode;
                //this.selectedTreeNode = (XTreeNode)this.selectedTreeNode.NextNode;
                showSelectedNode();
            }
        }

        private void loadMoulesDefinition()
        {
            this.cbModule.Items.Clear();

            /*if (this.selectedTreeNode.xnode is XMLGenerAttribute ||
                this.selectedTreeNode.xnode is XMLGenerTextNode ||
                this.selectedTreeNode.xnode is XMLGenerElement)*/
            if (selectedNodeIsText)
            {
                XMLGenerNode node = this.selectedTreeNode.xnode;
                string nodeType = node.contentType;
                string moduleId = node.module;
                XDataType dataType = doc.getAllDataTypes().getItem(nodeType) as XDataType;
                XModuleDefinitionInstance selectedMod = null;
                //List<XModuleDefinitionInstance> list = new List<XModuleDefinitionInstance>();
                List<XModuleDefinitionInstance> list = (dataType!=null)?dataType.modules:null;
                if (list != null)
                {
                    foreach (XModuleDefinitionInstance mod in list)
                    {
                        /*if (typeCanGenerated(mod.restirction, nodeType)) 
                            list.Add(mod);*/
                        if (mod.id == moduleId)
                            selectedMod = mod;
                    }
                    this.cbModule.Items.AddRange(list.ToArray());
                }
                //if (selectedMod != null && typeCanGenerated(selectedMod.restirction, nodeType))
                if (selectedMod != null )
                    this.cbModule.SelectedItem = selectedMod;
                else
                {
                    //this.cbModule.SelectedItem = null;
                    this.cbModule.SelectedIndex = -1;
                    this.cbModule.Text = "";
                    if (lastModuleEditor!=null)
                        lastModuleEditor.Visible = false;
                }
                if (lastModuleEditor!= null)
                    this.lastModuleEditor.setXNode(this.selectedTreeNode.xnode);
            }
            else if (lastModuleEditor != null)
            {
                lastModuleEditor.Visible = false;
                lastModuleEditor = null;
            }

        }

        private XModuleEditor lastModuleEditor = null;
        private Dictionary<string, XModuleEditor> modPanels = new Dictionary<string, XModuleEditor>();

        private void cbModule_SelectedIndexChanged(object sender, EventArgs e)
        {
            /*if (this.selectedTreeNode.xnode is XMLGenerAttribute ||
                this.selectedTreeNode.xnode is XMLGenerTextNode ||
                this.selectedTreeNode.xnode is XMLGenerElement)*/
            if (selectedNodeIsText)
            {
                XMLGenerNode node = this.selectedTreeNode.xnode ;
                XModuleDefinitionInstance selectedMod = (XModuleDefinitionInstance)this.cbModule.SelectedItem;
                if (selectedMod != null)
                {
                    node.module = selectedMod.id;
                    if (lastModuleEditor != null)
                        this.lastModuleEditor.Visible = false;
                    if (modPanels.ContainsKey(selectedMod.id))
                    {
                        this.lastModuleEditor = this.modPanels[selectedMod.id];
                    }
                    else
                    {
                        XModuleEditor newModuleEditor = new XModuleEditor();
                        newModuleEditor.Dock = System.Windows.Forms.DockStyle.Fill;
                        newModuleEditor.Location = new System.Drawing.Point(3, 16);
                        newModuleEditor.Name = "moduleEditor" + selectedMod.id;
                        newModuleEditor.Size = new System.Drawing.Size(295, 170);
                        newModuleEditor.createComponentsByModule(selectedMod);
                        moduleBox.Controls.Add(newModuleEditor);
                        modPanels.Add(selectedMod.id, newModuleEditor);
                        this.lastModuleEditor = newModuleEditor;
                    }
                    this.lastModuleEditor.Visible = true;
                    this.lastModuleEditor.setXNode(this.selectedTreeNode.xnode);
                }
                else 
                {
                    if (lastModuleEditor != null)
                    {
                        lastModuleEditor.Visible = false;
                        lastModuleEditor = null;
                    }
                }

            }else if (lastModuleEditor != null)
            {
                lastModuleEditor.Visible = false;
                lastModuleEditor = null;
            }
        }

        private bool typeCanGenerated(XModuleRestrictions modRestriction, string dataType)
        {
            if (modRestriction == null)
                return true;
            XDataTypeCollection col = doc.getAllDataTypes();
            XDataType currentType = col.getItem(dataType) as XDataType;
            XDataType nodebaseType = currentType;
            while (nodebaseType != null && !nodebaseType.isBaseType)
            {
                nodebaseType = nodebaseType.parentDataType;
            }
            if (nodebaseType == null)
                nodebaseType = col.getItem("any") as XDataType;

            XDataType moduleType = col.getItem(modRestriction.dataType) as XDataType;
            XDataType modulebaseType = currentType;
            while (nodebaseType != null && !nodebaseType.isBaseType)
            {
                if (nodebaseType.name == dataType)
                    return true;
                nodebaseType = nodebaseType.parentDataType;
            }
            if (nodebaseType == null)
                nodebaseType = col.getItem("any") as XDataType;

            return false;
        }


        private void tbOutId_TextChanged(object sender, EventArgs e)
        {
            if (this.doc == null)
                return;
            this.doc.outId = tbOutId.Text;
        }

        private void refreshIncludedFiles()
        {
            this.lbInclude.Items.Clear();
            TemplateFileInfo[] includeFiles = doc.getIncludeFiles();
            if (includeFiles != null)
                this.lbInclude.Items.AddRange(includeFiles);
        }


        private void btAddTemplate_Click(object sender, EventArgs e)
        {
            if (tbIncludeFile.Text.Length < 1)
                return;

            string filePath = DirectoriesUtil.combinePath(this.doc.sourceDirectory, tbIncludeFile.Text);
            FileInfo fi = new FileInfo(filePath);
            if (!fi.Exists)
            {
                XLogger.addError(this.GetType().ToString(), "File " + tbIncludeFile.Text + " does not exist");
                return;
            }

            if (doc.addIncludeFile(tbIncludeFile.Text))
            {
                refreshIncludedFiles();
            }
             
        }

        private void btRemoveTemplate_Click(object sender, EventArgs e)
        {
            if (lbInclude.SelectedItem != null)
            {
                doc.removeIncludeFile((TemplateFileInfo)lbInclude.SelectedItem);
                refreshIncludedFiles();
            }

        }

        private static string templatePath = XMLGener.Utils.DirectoriesUtil.templatesDir.FullName+Path.DirectorySeparatorChar;

        private void btSelectIncludeFile_Click(object sender, EventArgs e)
        {
            if (openXTLDialog.ShowDialog() == DialogResult.OK )
            {
                
                string filePath = openXTLDialog.FileName;
                filePath = DirectoriesUtil.getRelativePath(this.doc.sourceDirectoryInfo, filePath);
                tbIncludeFile.Text = filePath;                
            }
            

        }

        private void lbInclude_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lbInclude.SelectedItem == null)
                return;
            TemplateFileInfo templFI = lbInclude.SelectedItem as TemplateFileInfo;
            if (templFI.fileExists && openDocumentEvent != null)
                openDocumentEvent(this, templFI.absolutePath);

        }

        private void node_CheckedChanged(object sender, EventArgs e)
        {
            if (programmaticallyChange)
                return;
            XMLGenerRangeElement xelem = this.selectedTreeNode.xnode as XMLGenerRangeElement;
            if (xelem == null)
                return;
            if (sender == chbFrequency)
            {
                xelem.useFrequency = chbFrequency.Checked;
            }
            else if (sender == chbUseFanout)
            {
                xelem.useFanout = chbUseFanout.Checked;
            }
            else if (sender == chbDepth)
            {
                xelem.useDepth = chbDepth.Checked;
            }
            showSelectedNode();
        }

     
        private void btOutputFile_Click(object sender, EventArgs e)
        {
            try
            {
                selectOutputFile.FileName = this.doc.getMainElement().name.Replace(':','_') + ".xml";
                if (selectOutputFile.ShowDialog() == DialogResult.OK)
                {

                    string filePath = selectOutputFile.FileName;
                    filePath = DirectoriesUtil.getRelativePath(DirectoriesUtil.currentDir, filePath);
                    tbOutputFile.Text = filePath;
                    doc.outFile = filePath;
                }
            }
            catch (Exception ex)
            {
                XLogger.addError(this.GetType().ToString(), ex.Message);
            }
        }

        private void tbRanomInit_ValueChanged(object sender, EventArgs e)
        {
            doc.randomInit = Convert.ToInt32(tbRanomInit.Value);
        }

        private void tbOutputFile_TextChanged(object sender, EventArgs e)
        {
                string filePath = tbOutputFile.Text;
                filePath = DirectoriesUtil.getRelativePath(DirectoriesUtil.currentDir, filePath);
                tbOutputFile.Text = filePath;
                doc.outFile = filePath;
        }

        private void rbGenerXSD_CheckedChanged(object sender, EventArgs e)
        {
            if (rbGenerXSD.Checked)
                this.doc.outSchemeType = "xsd";
            else if (rbGenerNone.Checked)
                this.doc.outSchemeType = "none";
            else
                this.doc.outSchemeType = "dtd";
        }



        private void refreshPreGeneratedFiles()
        {
            lbPreGenerate.Items.Clear();
            TemplateFileInfo[] preGenerateFiles = doc.getPreGeneratedFiles();
            if (preGenerateFiles != null)
                this.lbPreGenerate.Items.AddRange(preGenerateFiles);

        }
        private void btAddPregenFile_Click(object sender, EventArgs e)
        {
            if (tbPregenFile.Text.Length < 1)
                return;

            string filePath = DirectoriesUtil.combinePath(this.doc.sourceDirectory, tbPregenFile.Text);
            FileInfo fi = new FileInfo(filePath);
            if (!fi.Exists)
            {
                XLogger.addError(this.GetType().ToString(), "File " + tbPregenFile.Text + " does not exist");
                return;
            }

            if (doc.addPreGeneratedFiles(tbPregenFile.Text))
                refreshPreGeneratedFiles();
            
        }

        private void btRemovePregenFile_Click(object sender, EventArgs e)
        {
            if (lbPreGenerate.SelectedItem != null)
            {
                doc.removePreGeneratedFiles((TemplateFileInfo)lbPreGenerate.SelectedItem);
                refreshPreGeneratedFiles();
            }

        }

        private void btSelectPregenFile_Click(object sender, EventArgs e)
        {
            if (openXTLDialog.ShowDialog() == DialogResult.OK)
            {

                string filePath = openXTLDialog.FileName;
                filePath = DirectoriesUtil.getRelativePath(doc.sourceDirectoryInfo, filePath);
                tbPregenFile.Text = filePath;
            }

        }

        private void lbPreGenerate_DoubleClick(object sender, EventArgs e)
        {

        }

        private XModuleEditor lastOutModuleEditor = null;
        private Dictionary<string, XModuleEditor> modOutPanels = new Dictionary<string, XModuleEditor>();

        private void cbOutputModules_SelectedIndexChanged(object sender, EventArgs e)
        {
            // selectedTreeNode.xnode.contentType = (string)cbNodeType.SelectedItem;


            XModuleOutputInstance selectedMod = (XModuleOutputInstance)this.cbOutputModules.SelectedItem;
            if (selectedMod != null && selectedMod.id!=null)
            {
                doc.module = selectedMod.id;
                if (lastOutModuleEditor != null)
                    this.lastOutModuleEditor.Visible = false;
                if (modOutPanels.ContainsKey(selectedMod.id))
                {
                    this.lastOutModuleEditor = this.modOutPanels[selectedMod.id];
                }
                else
                {
                    XModuleEditor newModuleEditor = new XModuleEditor();
                    newModuleEditor.Dock = System.Windows.Forms.DockStyle.Fill;
                    newModuleEditor.Location = new System.Drawing.Point(3, 16);
                    newModuleEditor.Name = "moduleEditor" + selectedMod.id;
                    newModuleEditor.Size = new System.Drawing.Size(295, 170);
                    newModuleEditor.createComponentsByModule(selectedMod);
                    outputModuleBox.Controls.Add(newModuleEditor);
                    modOutPanels.Add(selectedMod.id, newModuleEditor);
                    this.lastOutModuleEditor = newModuleEditor;
                }
                this.lastOutModuleEditor.Visible = true;
                this.lastOutModuleEditor.setXNode(this.doc);
            }
            else
            {
                doc.module = "" ;
                if (lastOutModuleEditor != null)
                {
                    lastOutModuleEditor.Visible = false;
                    lastOutModuleEditor = null;
                }
            }

            

        }

        private void tcbNodeType_ValueChanged(object sender, EventArgs e)
        {

            if (programmaticallyChange)
                return;
            XTreeNode node = tcbNodeType.SelectedNode as XTreeNode;
            if (node != null)
                selectedTreeNode.xnode.contentType = node.xnode.name;
            else
                selectedTreeNode.xnode.contentType = "";

            selectedTreeNode.refresh();
            loadMoulesDefinition();
            if (selectedTreeNode.xnode is XMLGenerElement)
            {
                XTreeNode.refreshTreeStructure(selectedTreeNode);
            }
            this.showSelectedNode();
        }

        private void tcbNodeInherit_ValueChanged(object sender, EventArgs e)
        {
            if (programmaticallyChange)
                return;
            XTreeNode node = tcbNodeInherit.SelectedNode as XTreeNode ;
            if (node!=null)
                selectedTreeNode.xnode.parentTypeName = node.xnode.name;
            else
                selectedTreeNode.xnode.parentTypeName = "";

            selectedTreeNode.refresh();
            loadMoulesDefinition();
            if (selectedTreeNode.xnode is XMLGenerElement)
            {
                XTreeNode.refreshTreeStructure(selectedTreeNode);
            }

            this.showSelectedNode();
            
            
        }

        private void tbId_TextChanged(object sender, EventArgs e)
        {

            if (programmaticallyChange)
                return;
            selectedTreeNode.xnode.id = tbId.Text;
        }

        private void lbPreGenerate_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lbPreGenerate.SelectedItem == null)
                return;
            TemplateFileInfo templFI = lbPreGenerate.SelectedItem as TemplateFileInfo;
            if (templFI.fileExists && openDocumentEvent != null)
                openDocumentEvent(this, templFI.absolutePath);
        }

        private void pDataType_Paint(object sender, PaintEventArgs e)
        {

        }

        
        private XModuleEditor lastSecondOutModuleEditor = null;
        private Dictionary<string, XModuleEditor> modSecondOutPanels = new Dictionary<string, XModuleEditor>();


        private void cbFinalModule_SelectedIndexChanged(object sender, EventArgs e)
        {

            XModuleOutputInstance selectedMod = (XModuleOutputInstance)this.cbFinalModule.SelectedItem;
            if (selectedMod != null && selectedMod.id!=null)
            {
                doc.secondModule = selectedMod.id;
                if (lastSecondOutModuleEditor != null)
                    this.lastSecondOutModuleEditor.Visible = false;
                if (modSecondOutPanels.ContainsKey(selectedMod.id))
                {
                    this.lastSecondOutModuleEditor = this.modSecondOutPanels[selectedMod.id];
                }
                else
                {
                    XModuleEditor newModuleEditor = new XModuleEditor();
                    newModuleEditor.Dock = System.Windows.Forms.DockStyle.Fill;
                    newModuleEditor.Location = new System.Drawing.Point(3, 16);
                    newModuleEditor.Name = "moduleEditor" + selectedMod.id;
                    newModuleEditor.Size = new System.Drawing.Size(295, 170);
                    newModuleEditor.createComponentsByModule(selectedMod);
                    secondOutputModuleBox.Controls.Add(newModuleEditor);
                    modSecondOutPanels.Add(selectedMod.id, newModuleEditor);
                    this.lastSecondOutModuleEditor = newModuleEditor;
                }
                this.lastSecondOutModuleEditor.Visible = true;
                this.lastSecondOutModuleEditor.setXNode(this.doc.secondOutputElem);
            }
            else
            {
                doc.module = "" ;
                if (lastSecondOutModuleEditor != null)
                {
                    lastSecondOutModuleEditor.Visible = false;
                    lastSecondOutModuleEditor = null;
                }
            }



        }

        
      

       
    }
}
